#include "Map.h"

Map::Map()
{
	//Take some default values;
	width = MAP_DEFAULT_WIDTH;
	height = MAP_DEFAULT_HEIGHT;
	m_redrawMap = true;


	//Allocate space in the 2d array.
	m_layer = new Map_Cell * [height];
	for (int y = 0; y < height; ++y)
	{
		m_layer[y] = new Map_Cell[width];	
	}

	//Now that space is allocated, lets fill it.
	for (int y = 0; y < height; ++y)
	{
		for (int x = 0; x < width; ++x)
		{
			m_layer[y][x].setIcon('#');
			m_layer[y][x].setColor(WALL_COLOR);
		}
	}
	generateDungeon(10, 10);
}

Map::~Map()
{
	if (m_layer)
	{
		for (int y = 0; y < height; ++y)
		{
			delete [] m_layer [y];
		}
		delete [] m_layer;
	}
	m_layer = 0;
}

void Map::handleInput(char a_input)
{

}

void Map::updateMap(int a_x, int a_y)
{
	//Clear all the map flags
	for(int y = 0; y < height; ++y){
		for(int x = 0; x < width; ++x){
			if (m_layer[y][x].isVisible() == true){
				m_layer[y][x].setVisible(false);
				redrawAt(x, y);
			}
		}
	}
	//Use Brenesham (sp?) circle algorithm to do circular LOS)


	//Make visible the cells the player can see
	for (int y = a_y - 5; y < a_y + 6; ++y){
		for (int x = a_x - 5; x < a_x + 6; ++x){
			if (y >= 0 && y < height && x >= 0 && x < width){
				m_layer[y][x].setMapped(true);
				m_layer[y][x].setVisible(true);
				redrawAt(x, y);
			}
		}
	}	
}

void Map::draw()
{
	if (m_redrawMap)
	{
		//Loop through m_layer, drawing each element in turn
		for (int y = 0; y < height; ++y)
		{
			for (int x = 0; x < width; ++x)
			{
				//Move cursor to the beginning of the screen before redraw.
				COORD temp = {x, y};
				SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), temp);

				if (m_layer[y][x].isMapped())
					m_layer[y][x].draw();
				else
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x00);
					putchar(' ');
			}
			putchar('\n');
		}
		m_redrawMap = false;
	}
}



void Map::redraw()
{
	m_redrawMap = true;
}

void Map::redrawAt(int a_x, int a_y)
{
	//Move the console cursor to the selected point
	COORD temp = {a_x, a_y};
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), temp);
	//Redraw the area at that point
	//if (m_layer[a_y][a_x].isMapped())
		m_layer[a_y][a_x].draw();
}

char Map::getLocationAt(int a_x, int a_y)
{
	return m_layer[a_y][a_x].getIcon();
}

void Map::generateDungeon(int a_NumOfNodes, int a_NumOfRooms)
{
	//Idiot-proof the paramaters
	if (a_NumOfNodes < 0)
		a_NumOfNodes = 0;
	if (a_NumOfRooms < 0)
		a_NumOfRooms = 0;
	if (a_NumOfRooms > a_NumOfNodes)
		a_NumOfRooms = a_NumOfNodes;
	//Generate a list of random points [a_NumOfNodes] long
	Location * NodeList;///Create a pointer to hold our array
	NodeList = new Location[a_NumOfNodes];///New up the array

	for (int i = 0; i < a_NumOfNodes; ++i)	//Generate the random points
	{
		NodeList[i].setX(rand() % MAP_DEFAULT_WIDTH);
		NodeList[i].setY(rand() % MAP_DEFAULT_HEIGHT);
	}

	//Draw corridors through all the points, looping back to the first
	Location CorridorCarver;	///A 'carving head' that we will move around.
	Location Target;			///A target to carve to.
	for (int i = 0; i < a_NumOfNodes; ++i)
	{
		///Initialize the location of the CorridorCarver
		CorridorCarver = NodeList[i];

		///Set the 'carve-to' target
		if (i < a_NumOfNodes - 1/* Not the last node */)
			Target = NodeList[i + 1];
		else  /* Is the last node */
			Target = NodeList[0];
		//Carve vertically first
		do
		{
			m_layer[CorridorCarver.getY()][CorridorCarver.getX()].setIcon('.');	///Carve a space of corridor
			m_layer[CorridorCarver.getY()][CorridorCarver.getX()].setColor(DEFAULT_COLOR);

			if (Target.getY() > CorridorCarver.getY())						///Move the corridor carver to the next space
				CorridorCarver.setY(CorridorCarver.getY() + 1);
			else
				CorridorCarver.setY(CorridorCarver.getY() - 1);
		}while(CorridorCarver.getY() != Target.getY());

		//Then horizontally
		do
		{
			m_layer[CorridorCarver.getY()][CorridorCarver.getX()].setIcon('.');	///Carve a space of corridor
			m_layer[CorridorCarver.getY()][CorridorCarver.getX()].setColor(DEFAULT_COLOR);

			if (Target.getX() > CorridorCarver.getX())						///Move the corridor carver to the next space
				CorridorCarver.setX(CorridorCarver.getX() + 1);
			else
				CorridorCarver.setX(CorridorCarver.getX() - 1);
		}while(CorridorCarver.getX() != Target.getX());
	}

	//Generate [a_NumOfRooms] random nodes
	Location * RoomNodes;
	RoomNodes = new Location[a_NumOfRooms];

	for (int i = 0; i < a_NumOfRooms; ++i)
	{
		RoomNodes[i].setX(rand() % MAP_DEFAULT_WIDTH);
		RoomNodes[i].setY(rand() % MAP_DEFAULT_HEIGHT);
	}

	//Using the nodes as an anchor point, carve out a random size rectangular room for each.
	Location UpLeftBound, BottomRightBound;	///Two areas to mark out our corners
	for (int i = 0; i < a_NumOfRooms; ++i)
	{
		///Initialize our room corners to the node value
		UpLeftBound = RoomNodes[i];
		BottomRightBound = RoomNodes[i];

		///Choose a small random x & y distance for the UpperLeftCorner to move
		UpLeftBound.setY(UpLeftBound.getY() - (ROOM_SIZE_VARIANCE));
		UpLeftBound.setX(UpLeftBound.getX() - (ROOM_SIZE_VARIANCE));
		///Check to make sure the room is still in map boundaries.  Force to fit.
		if (UpLeftBound.getX() < 0)
			UpLeftBound.setX(0);
		if (UpLeftBound.getY() < 0)
			UpLeftBound.setY(0);

		///Choose a small random x & y distance for the BottomRightCorner to move
		BottomRightBound.setY(BottomRightBound.getY() + (ROOM_SIZE_VARIANCE));
		BottomRightBound.setX(BottomRightBound.getX() + (ROOM_SIZE_VARIANCE));
		///Check to make sure the room is still in map boundaries.  Force to fit.
		if (BottomRightBound.getX() > MAP_DEFAULT_WIDTH)
			BottomRightBound.setX(MAP_DEFAULT_WIDTH);
		if (BottomRightBound.getY() > MAP_DEFAULT_HEIGHT)
			BottomRightBound.setY(MAP_DEFAULT_HEIGHT);

		///Loop through from upperleftbound to bottonrightbound, changing the map to '.';
		for (int y = UpLeftBound.getY(); y < BottomRightBound.getY(); ++y)
		{
			for (int x = UpLeftBound.getX(); x < BottomRightBound.getX(); ++x)
			{
				m_layer[y][x].setIcon('.');
				m_layer[y][x].setColor(DEFAULT_COLOR);
			}
		}
	}

	//Free up all that allocated data
	delete [] NodeList;
	NodeList = 0;
	delete [] RoomNodes;
	RoomNodes = 0;
}